﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Collections.ObjectModel;
using ThreeByte.ActiveDeck.Data.UserResponse;

namespace ThreeByte.ActiveDeck.Config
{
    public class MultipleChoiceConfig : PageConfig
    {

        #region Public Properties

        private string _question;
        public string Question {
            get {
                return _question;
            }
            set {
                _question = value;
                NotifyPropertyChanged("Question");
            }
        }

        private ObservableCollection<Answer> _answers = new ObservableCollection<Answer>();
        public ObservableCollection<Answer> Answers {
            get {
                return _answers;
            }
            set {
                _answers = value;
                NotifyPropertyChanged("Answers");
                NotifyPropertyChanged("HasAnswer");
            }
        }

        private bool _oneTime;
        public bool OneTime {
            get {
                return _oneTime;
            }
            set {
                _oneTime = value;
                NotifyPropertyChanged("OneTime");
            }
        }

        private string _correctAnswerOverride;
        public string CorrectAnswerOverride {
            get {
                return _correctAnswerOverride;
            }
            set {
                _correctAnswerOverride = value;
                NotifyPropertyChanged("CorrectAnswerOverride");
            }
        }

        private string _incorrectAnswerOverride;
        public string IncorrectAnswerOverride {
            get {
                return _incorrectAnswerOverride;
            }
            set {
                _incorrectAnswerOverride = value;
                NotifyPropertyChanged("IncorrectAnswerOverride");
            }
        }

        private bool _instantFeedback;
        public bool InstantFeedback {
            get {
                return _instantFeedback;
            }
            set {
                _instantFeedback = value;
                NotifyPropertyChanged("InstantFeedback");
            }
        }

        public bool HasAnswer {
            get { //If there are no answers, provide no feedback
                return !(Answers.Count == 0);                
            }
        }

        #endregion Public Properties

        public MultipleChoiceConfig() {
            LayoutOrientation = Content.Orientation.Portrait; //By Default
        }

        public MultipleChoiceConfig(XElement node, Dictionary<Guid, GraphicResource> resources)
            : base(node, resources) {
            Question = Uri.UnescapeDataString(node.Element(ns + "Question").Attribute("Text").Value);

            if(node.Attribute("OneTime") != null) {
                OneTime = bool.Parse(node.Attribute("OneTime").Value);
            }
            if(node.Attribute("InstantFeedback") != null) {
                InstantFeedback = bool.Parse(node.Attribute("InstantFeedback").Value);
            }

            if(node.Element(ns + "CorrectAnswer") != null) {
                CorrectAnswerOverride = Uri.UnescapeDataString(node.Element(ns + "CorrectAnswer").Attribute("Text").Value);
            }
            if(node.Element(ns + "IncorrectAnswer") != null) {
                IncorrectAnswerOverride = Uri.UnescapeDataString(node.Element(ns + "IncorrectAnswer").Attribute("Text").Value);
            }

            foreach (XElement a in node.Elements(ns + "Answer")) {
                Answer newAnswer = new Answer(a.Attribute("Text").Value);
                newAnswer.IsCorrect = bool.Parse(a.Attribute("IsCorrect").Value);
                Answers.Add(newAnswer);
            }

        }

        public override XElement ToXml() {
            XElement node = base.ToXml();
            node.Add(new XElement(ns + "Question", new XAttribute("Text", Uri.EscapeDataString(Question ?? string.Empty))));
            if(OneTime) {
                node.Add(new XAttribute("OneTime", OneTime));
            }

            //TODO: Serialize the answers
            foreach (Answer a in Answers) {
                node.Add(new XElement(ns + "Answer", new XAttribute("Text", a.Text ?? string.Empty),
                                                        new XAttribute("IsCorrect", a.IsCorrect)));
            }
            
            if(InstantFeedback) {
                node.Add(new XAttribute("InstantFeedback", InstantFeedback));
            }
            if(!string.IsNullOrWhiteSpace(CorrectAnswerOverride)) {
                node.Add(new XElement(ns + "CorrectAnswer", new XAttribute("Text", CorrectAnswerOverride)));
            }
            if(!string.IsNullOrWhiteSpace(IncorrectAnswerOverride)) {
                node.Add(new XElement(ns + "IncorrectAnswer", new XAttribute("Text", IncorrectAnswerOverride)));
            }

            return node;
        }

        public MultipleChoiceUserData InitUserData() {
            MultipleChoiceUserData userData = new MultipleChoiceUserData(1);
            int i = 0;
            foreach(Answer a in Answers){
                userData.Answers.Add(new MultipleChoiceAnswerData(++i, a.IsCorrect));
            }

            return userData;
        }

        public override XElement GetReportContext(AggregateUserData userData) {
            XElement data = userData.ToXml();
            data.Add(new XAttribute("Question", Question));
            foreach(XElement el in data.Elements(ns + "Answer")) {
                int value = int.Parse(el.Attribute("Value").Value);
                string theValue = Answers[value - 1].Text;
                el.Add(new XAttribute("Text", theValue));
            }

            return data;
        }

        public XElement GetGradingConfig() {
            XElement gradeNode = new XElement(ns + "Grading");
            if(HasAnswer && InstantFeedback) {
                gradeNode.Add(new XAttribute("InstantFeedback", InstantFeedback));
            }
            string correctAnswerFeedback = CorrectAnswerOverride;
            if(string.IsNullOrWhiteSpace(correctAnswerFeedback)) {
                correctAnswerFeedback = GetDefaultCorrectText();
            }
            gradeNode.Add(new XAttribute("CorrectAnswerFeedback", Uri.EscapeDataString(correctAnswerFeedback)));

            string incorrectAnswerFeedback = IncorrectAnswerOverride;
            if(string.IsNullOrWhiteSpace(incorrectAnswerFeedback)) {
                incorrectAnswerFeedback = GetDefaultIncorrectText();
            }
            gradeNode.Add(new XAttribute("IncorrectAnswerFeedback", Uri.EscapeDataString(incorrectAnswerFeedback)));

            gradeNode.Add(new XElement(ns + "Question", new XAttribute("Text", Question)));
            for(int i = 0; i < Answers.Count; i++) {
                if(Answers[i].IsCorrect) {
                    gradeNode.Add(new XElement(ns + "CorrectAnswer", new XAttribute("Value", i + 1)));
                }
            }

            for(int i = 0; i < Answers.Count; i++) {
                gradeNode.Add(new XElement(ns + "Answer", new XAttribute("Text", Answers[i].Text ?? string.Empty), new XAttribute("ID",i+1)));
            }

            return gradeNode;
        }

        internal string GetDefaultCorrectText() {
            return "That's Correct!";
        }

        internal string GetDefaultIncorrectText() {
            List<string> correctAnswers = new List<string>();

            for(int i = 0; i < Answers.Count; i++) {
                if(Answers[i].IsCorrect) {
                    correctAnswers.Add(Answers[i].Text);
                }
            }

            string text = string.Format("Sorry, there is no correct answer.");
            if(correctAnswers.Count == 1) {
                text = string.Format("Sorry, the correct answer is {0}", correctAnswers[0]);
            } else if(correctAnswers.Count > 1) {
                text = string.Format("Sorry, the correct answer is ");

                int i;
                bool isFirst = true;
                for(i = 0; i < correctAnswers.Count - 1; i++) {
                    if(!isFirst) {
                        text += string.Format(", ");
                    }
                    isFirst = false;
                    text += string.Format("{0}", correctAnswers[i]);
                }
                text += string.Format(" and {0}", correctAnswers[i]);
            }

            return text;
        }
    }

    public class Answer
    {
        public Answer(string text = null) {
            Text = text;
        }

        public string Text { get; set; }
        public bool IsCorrect { get; set; }
    }
}
